#include <unistd.h>
#include <iostream>
using namespace std;
#include <string>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/wait.h>

const int basesize = 1024;
const int gnum = 64;

int gargc = 0;
char* gargv[gnum];
char* genv[basesize];


char pwdenv[basesize];
char cwdarr[basesize];

string GetUName()
{
    char* name = getenv("USER");
    if (name == nullptr) return "NONE";
    return name;
}

//修改pwd
void UpdateEnv(char* chpwd)
{
    for (int i = 0; genv[i]; i++)
    {
        if (strncmp("PWD",genv[i],3) == 0)
        {
            snprintf(genv[i],basesize,"PWD=%s",chpwd);
            return;
        }
    }
}
//string GetPwd()
//{
//    if (!getcwd(cwdarr,basesize)) return "NONE";
//    snprintf(pwdenv,basesize,"PWD=%s",cwdarr);
//    UpdateEnv(cwdarr); //维护环境变量
//    return cwdarr;
//}

string GetPwd()
{
    if (!getcwd(cwdarr,basesize)) return "NONE";
    snprintf(pwdenv,basesize,"PWD=%s",cwdarr);
    putenv(pwdenv);
    return cwdarr;
    //char * pwd = getenv("PWD");
    //if (pwd == nullptr) return "NONE";
    //return pwd;
}
string GetHostname()
{
    char* hostname = getenv("HOSTNAME");
    if (hostname == nullptr) return "NONE";
    return hostname;
}


bool GetCmdLine(char* cmdline)
{
   char* ret  = fgets(cmdline,basesize,stdin);
   if (ret == nullptr || strlen(cmdline) == 1) return false;
   cmdline[strlen(cmdline)-1] = '\0'; //消除最后一个\n
   return true;
}

void PrinfCmdLine()
{
    printf("[%s@%s %s]# ",GetUName().c_str(),GetHostname().c_str(),GetPwd().c_str());
    fflush(stdout);
}

bool ParseCmdLine(char* cmdline)
{
    gargc = 0;
    memset(gargv,0,sizeof(gargv)); //重置命令行参数表

    const char* sep = " ";         //strtok以空格为分割符

    char* tmp = strtok(cmdline,sep);
    if (tmp == nullptr) return false;
    gargv[gargc] = (char*)malloc(strlen(tmp) + 1);
    strcpy(gargv[gargc],tmp);
    gargc++;
    while((bool)(tmp = strtok(nullptr,sep)))
    {
        gargv[gargc] = (char*)malloc(strlen(tmp)+1);
        strcpy(gargv[gargc],tmp);
        gargc++;
    }
    gargv[gargc] = nullptr;   //命令行参数表最后需要添加一个空指针
    return true;
}

void ExcuteCmdline()
{
    pid_t id = fork();
    if (id == 0)
    {
        if (execvpe(gargv[0],gargv,genv) < 0)
        {
            printf("commend not found\n");
            exit(-1);
        }
        exit(0);
    }
    int status;
    pid_t w = waitpid(id,&status,0);
    if(w < 0)
    {
        printf("等待失败!\n");
    }
}

void AddEnv(char* newenv)
{
    int index = 0;
    while(genv[index])
    {
        ++index;
    }
    genv[index] = (char*)malloc(strlen(newenv)+1);
    strcpy(genv[index],newenv);
}


void PrintEnv()
{
    int index = 0;
    while(genv[index])
    {
        printf("%s\n", genv[index]);
        index++;
    }
}


bool CheckAndExcuteCmdline()
{
    int ret= 0 ;
    if (strcmp("cd",gargv[0]) == 0)
    {
        if (gargc == 2)
        {

            if ((bool)(ret = (chdir(gargv[1]) == -1))) cout << "No Such file or directory!" << endl;
            return true;
        }
    }
    else if(strcmp("export",gargv[0]) == 0)
    {
        if (gargc == 2)
        {
            AddEnv(gargv[1]);
            return true;
        }
    }
    else if(strcmp("env",gargv[0]) == 0)
    {
        if (gargc == 1)
        {
            PrintEnv();
            return true;
        }
    }

    return false;
}

void InitialEnv()
{
    extern char** environ;
    int index  = 0;
    while(environ[index])
    {
        genv[index] = (char*)malloc(strlen(environ[index])+1);
        strcpy(genv[index],environ[index]);
        index++;
    }
    genv[index] = nullptr;
}




int main()    
{    
    InitialEnv();    
    char cmdline[basesize];    
   //[xhm@iZ2zee7b26b1g3ujcquk70Z newshell]$     
   while(true)    
   {                                             
        //1.打印命令行                                
        PrinfCmdLine();    
        //2.命令行输入    
        if(!GetCmdLine(cmdline))    
        {               
            continue;               
        }                                  
        //3.解析命令行    
        if (!ParseCmdLine(cmdline)) continue;    
        if (CheckAndExcuteCmdline()) continue; 
        //4.运行程序                 
        ExcuteCmdline();    
   }    
    return 0;    
}    

